/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package Modele;

import java.awt.Point;
import java.io.Serializable;
import java.util.Observable;

/**
 * Classe représentant une cellule du jeu de la vie
 * @author FERRIER/NONGLATON
 * 
 */
public class Cellule extends Observable implements Serializable {

    private Boolean etat;
    private Boolean etatSuivant;
    private Point coordonnees;
    private Environnement env;
    private Cellule[] voisins;
    private int nbVoisins;

    /**
     * Créé une nouvelle cellule
     * @param etat état de la cellule créée
     * @param coordonnees coordonnées de la cellule créée
     * @param e l'environnement de la cellule
     */
    public Cellule(Boolean etat, Point coordonnees, Environnement e) {
        this.etat = etat;
        this.coordonnees = coordonnees;
        this.env = e;
        this.voisins = new Cellule[8];
        nbVoisins = 0;
    }

    // <editor-fold defaultstate="collapsed" desc="getters et setters">
    /**
     * Retourne les coordonnées de la cellule
     * @return un point représentant les coordonnées de la cellule
     */
    public Point getCoordonnees() {
        return coordonnees;
    }

    /**
     * Retourne l'état de la cellule
     * @return true si la cellule est vivante<br/>false si elle est morte
     */
    public Boolean getEtat() {
        return etat;
    }

    /**
     * Retourne les voisins de la cellule
     * @return un tableau contenant les cellules voisines
     */
    public Cellule[] getVoisins() {
        return voisins;
    }

    /**
     * Définit l'état de la cellule et prévient ses voisines de son changement d'état.<br/> 
     * Notifie aussi ses observateurs.<br/>
     * Ne modifie l'état de la cellule que si celui-ci est différent de l'état actuel
     * @param etat le nouvel état de la cellule
     */
    public void setEtat(Boolean etat) {
        if (etat != this.etat) {//si l'état change
            this.etat = etat;
            if (etat) {//si la cellule devient vivante
                env.getCellulesVivantes().add(this);
                for (Cellule cellule : voisins) {
                    cellule.addVoisin();
                }
            } else {
                env.getCellulesVivantes().remove(this);
                for (Cellule cellule : voisins) {
                    cellule.removeVoisin();
                }
            }

            //on notifie l'observateur
            setChanged();
            notifyObservers();
        }
    }

    /**
     * Définit les voisins de la cellule
     * @param voisins contient un tableau contenant les cellules voisines
     */
    public void setVoisins(Cellule[] voisins) {
        this.voisins = voisins;
    }

    /**
     * Retourne l'environnement de la cellule
     * @return l'environnement de la cellule
     */
    public Environnement getEnv() {
        return env;
    }

// </editor-fold>

    /**
     * Determine si la cellule vivra à la prochaine génération
     * Ancienne version
     * @return true si la cellule vivra et false si elle mourra
     */
//    public boolean survie() {
//        int nbVivante = nbVivanteAdjacente();
//        boolean vie = false;
//        if (etat) {//si la cellule est vivante
//
//            if (env.getRegle().survie.contains(nbVivante)) {
//                vie = true;
//            }
//
//        } else {//si la cellule est morte
//            if (env.getRegle().naissance.contains(nbVivante)) {
//
//                vie = true;
//            }
//
//        }
//        etatSuivant = vie;
//        return vie;
//    }


    /**
     * Determine si la cellule vivra à la prochaine génération
     * @return true si la cellule vivra et false si elle mourra
     */
    public boolean survie() {
        boolean vie = false;
        if (etat) {//si la cellule est vivante

            if (env.getRegle().getSurvie().contains(nbVoisins)) {
                vie = true;
            }

        } else {//si la cellule est morte
            if (env.getRegle().getNaissance().contains(nbVoisins)) {

                vie = true;
            }

        }
        etatSuivant = vie;
        return vie;
    }

    /**
     * Actualise l'état de la cellule pour la faire passer à la nouvelle génération
     * @return true si la cellule a changé d'état, false sinon
     */
    public Boolean changeEtat() {
        if (etat != etatSuivant) {
            this.setEtat(etatSuivant);
            return true;
        } else {
            return false;
        }
    }

    /**
     * Retourne le nombre de cellules voisines vivantes
     * @return le nombre de voisins vivants
     */
//    private int nbVivanteAdjacente() {
//        int nbViv = 0;
//        for (Cellule cel : voisins) {
//            if (cel.getEtat()) {
//                nbViv++;
//            }
//        }
//
//        return nbViv;
//    }

    /**
     * Augmente le nombre de voisins vivants
     */
    private synchronized void addVoisin() {
        nbVoisins++;
    }

    /**
     * Diminue le nombre de voisins vivants
     */
    private synchronized void removeVoisin() {
        nbVoisins--;
    }
}
